package com.usc.csci588.chaltrojan;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.ExecutionException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.speech.RecognizerIntent;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.Toast;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;
import com.usc.csci588.chaltrojan.location.map.CTItemizedOverlay;
import com.usc.csci588.chaltrojan.location.map.CTItemizedOverlay2;

public class SetDestinationMapActivity extends MapActivity {

	MapView mv = null;
	MapController mc = null;
	List<Overlay> mapOverlays = null;
	
	LinearLayout searchLayout = null;
	EditText searchFor = null;
	
	private Boolean showResults = null;
	Location myInitialLocation = null;
	static final int HIGH_ZOOM = 17;
	static final int MED_HIGH_ZOOM = 15;
	static final int MED_ZOOM = 12;
	static final int LOW_ZOOM = 7;
    private static final int RECOGNIZER_EXAMPLE = 1001;
    public static final int DEST_FINAL = 0;
    
    public Boolean getShowResults() {
		return showResults;
	}

	public void setShowResults(Boolean showResults) {
		this.showResults = showResults;
	}

	@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        new Handler();
        setContentView(R.layout.map_view_1);
        
        setShowResults(false);
        
        mv = (MapView) this.findViewById(R.id.map1);
        mv.setBuiltInZoomControls(true);
        mapOverlays = mv.getOverlays();
        searchFor = (EditText) findViewById(R.id.searchPlace);

        mv.setSatellite(false);
        mv.setClickable(true);
        //mv.setst
        
        ImageButton searchBtn = (ImageButton) findViewById(R.id.searchBtn);
        
        searchBtn.setOnClickListener(generateOnClickListener());
        
        searchLayout = (LinearLayout)findViewById(R.id.search);
        
        searchLayout.setPadding(0, 1, 0, 0);
        searchLayout.setBackgroundColor(Color.LTGRAY);
        //searchLayout.invalidate();
        
        mc = mv.getController();
		mc.setZoom(MED_ZOOM);
        
        LocationManager lm = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
        LocationListener ll = new LocationListener() {

			/**
			 * Most useful method - called whenever GPS changes location
			 * The center point is set to the new location whenever that happens
			 */
			@Override
			public void onLocationChanged(Location point) {
				//Log.d("maps","getShowResults() = "+getShowResults());
				if (getShowResults()) {
					return;
				}

				Log.d("maps","location changed - It is now "+
						point.getLatitude()+ " "+point.getLongitude());
				mapOverlays.clear();
				GeoPoint p =  createGeoPoint(point.getLatitude() , point.getLongitude() );
				if (!getShowResults()) {
					mc.animateTo(p);
					mc.setZoom(MED_HIGH_ZOOM);
				}
				setupOverlay(mv, p);
				
				/**
				 * This is for testing if we can show two points simultaneously
				 * //TODO - Remove after testing 
				 */

				/*
				List<GeoPoint> otherPoints = getOtherLocations(p);
				setupOverlay(mv, otherPoints);
		        //*/
				
				mv.invalidate();
				
			}

			@Override
			public void onProviderDisabled(String provider) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void onProviderEnabled(String provider) {
				// TODO Auto-generated method stub
				
			}

			@Override
			public void onStatusChanged(String provider, int status,
					Bundle extras) {
				// TODO Auto-generated method stub
			}
        	
        };
        
        /**
         * http://developer.android.com/guide/topics/location/strategies.html
         */
        lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 50, ll);
       
        myInitialLocation = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
        

        if (myInitialLocation == null) {
        	myInitialLocation = new Location("");
        	myInitialLocation.setLatitude(34.0);
        	myInitialLocation.setLongitude(-118.0);
        }
        
       GeoPoint p = createGeoPoint(myInitialLocation.getLatitude() , myInitialLocation.getLongitude() ); 
       mapOverlays.clear();
		setupOverlay(mv, p);       

       /**
        * This is for testing if we can show two points simultaneously
        * //TODO - Remove after testing 
        */
       
       /*
			GeoPoint p2 = new GeoPoint(
            (int) (intialLocation.getLatitude() * 1.00001 * 1e6), 
            (int) (intialLocation.getLongitude() * 1.00031 * 1e6) );
       		setupOverlay(mv, p2);

        //*/
       
		Log.d("maps","location p is Lat: "+
				myInitialLocation.toString() );
        
        mc.animateTo(p);        
        mv.invalidate();
        
        ImageButton voiceButton = (ImageButton) findViewById(R.id.voiceBtn);
        voiceButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                // RecognizerIntent prompts for speech and returns text
                try {
                Intent intent =
                   new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
                intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
                        RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
                intent.putExtra(RecognizerIntent.EXTRA_PROMPT,
                "Where to?");
                startActivityForResult(intent, RECOGNIZER_EXAMPLE);
                } catch (ActivityNotFoundException anfe) {
                	
                }
            }
        });
  

   }
    
    private GeoPoint createGeoPoint(double latitude, double longitude){
    	return new GeoPoint( (int) (latitude * 1E6 ),
				(int) (longitude * 1E6) );
    }
    
    /**
     * This is for search button, we click on it and we find out the 
     * route that we ought to take
     * @return
     */
    private View.OnClickListener generateOnClickListener(){
    	return new View.OnClickListener() {
    		 public void onClick(View v) {
                 // Perform action on click
 		        	Log.d("maps","Attempting to find places...");
    		        Geocoder geoCoder = new Geocoder(v.getContext());
					try {
						Log.d("maps","isPresent () --> " + Geocoder.isPresent());
						//List<Address> addresses = ReverseGeocode.getFromLocationName(searchFor.getText().toString(),5);
						Address[] addrs = new Address[5];
						Arrays.fill(addrs, null);
						GetLocationTask gtask = new GetLocationTask(searchFor.getText().toString(), addrs);
						gtask.execute().get();
						//List<Address> addresses = GetLocationTask.execute(runnable) .getFromLocationName(searchFor.getText().toString(),5);
						List<Address> addresses2 =  geoCoder.getFromLocationName(searchFor.getText().toString(),5);
						
						
//						List<Address> addresses = Arrays.asList(addrs);
//	    		        Log.d("maps","Found results = "+addresses.size());
//		                List<GeoPoint> geopoints = new ArrayList<GeoPoint>();
//	    		        setShowResults(false);
//						if(addresses.size() > 0)
//		                {
//					        mv.setSatellite(false);
//							for (int i=0; i<addresses.size(); i++) {
//								geopoints.add(createGeoPoint(addresses.get(i).getLatitude(), addresses.get(0).getLongitude() ));
//			    		        Log.d("maps","Result ["+i+"] = "+addresses.get(i).getLatitude()+ "  " + addresses.get(0).getLongitude());
//							
//								//TODO - Comment below part - this is only for testing
//								//i+= addresses.size();
//							}
//
//							//mapOverlays.clear();
//		                     
//							GeoPoint p = createGeoPoint(myInitialLocation.getLatitude() , myInitialLocation.getLongitude() ); 
//						   	mapOverlays.clear();
//							setupOverlay(mv, p);       
//
//							Drawable drawable = getResources().getDrawable(R.drawable.map_marker_search);
//							setupOverlay(mv, geopoints, drawable);
//							mc.animateTo(geopoints.get(0));
//							mc.setZoom(MED_ZOOM);
//							
//							//Toast.makeText(getApplicationContext(), "Total overlays = "+ mapOverlays.size() , Toast.LENGTH_LONG).show();
//							Toast.makeText(getApplicationContext(), addresses.size() + " results found!!", Toast.LENGTH_LONG).show();
//
//
//							mv.invalidate();
//							//searchFor.setText("");
//							Toast.makeText(getApplicationContext(), "Tap on a location to set it as destination", Toast.LENGTH_LONG).show();
//							
////							double fromLat = myInitialLocation.getLatitude();
////							double fromLon = myInitialLocation.getLongitude();
////							
////							double toLat = addresses.get(0).getLatitude();
////							double toLon = addresses.get(0).getLongitude();
////							
////							
////							displayRoute(fromLat, fromLon, toLat, toLon);
//		                }
//		                else
//		                {
//		                        AlertDialog.Builder adb = new AlertDialog.Builder(SetDestinationMapActivity.this);
//		                        adb.setTitle("Chal, Trojan!");
//		                        adb.setMessage("No results were found, please search again..");
//		                        adb.setPositiveButton("Close",null);
//		                        adb.show();
//		                }
		                
						
					} catch (IOException e) {
						// TODO Auto-generated catch block
						//Toast.makeText(getApplicationContext(), "Error in retrieving results from Google. Please try again...", Toast.LENGTH_LONG).show();
						Log.d("maps","Google ERR --> "+e.getMessage());
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (ExecutionException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}

             }

    	};
    }
    
	public void locationFound(Address address) {
		Log.d("maps","Now display search results...");
		double lat = address.getLatitude();
		double lng = address.getLongitude();
		
		if (lat == 0.0 && lng == 0.0){
            AlertDialog.Builder adb = new AlertDialog.Builder(SetDestinationMapActivity.this);
            adb.setTitle("Chal, Trojan!");
            adb.setMessage("No results were found, please search again..");
            adb.setPositiveButton("Close",null);
            adb.show();
		} else {
            List<GeoPoint> geopoints = new ArrayList<GeoPoint>();
	        setShowResults(false);
			geopoints.add(createGeoPoint(lat,lng));

			GeoPoint p = createGeoPoint(myInitialLocation.getLatitude() , myInitialLocation.getLongitude() ); 
		   	mapOverlays.clear();
		   	setupOverlay(mv, p);       

			Drawable drawable = getResources().getDrawable(R.drawable.map_marker_search);
			setupOverlay(mv, geopoints, drawable);
			mc.animateTo(geopoints.get(0));
			mc.setZoom(MED_ZOOM);
			
//			//Toast.makeText(getApplicationContext(), "Total overlays = "+ mapOverlays.size() , Toast.LENGTH_LONG).show();
//			Toast.makeText(getApplicationContext(), addresses.size() + " results found!!", Toast.LENGTH_LONG).show();

			mv.invalidate();
			//searchFor.setText("");
			Toast.makeText(getApplicationContext(), "Tap on a location to set it as destination", Toast.LENGTH_LONG).show();			
		}
		
	}
  

    
    @Override
    protected void onActivityResult(int requestCode,
                                    int resultCode, Intent data) {
    	//use a switch statement for more than one request code check
    	if (requestCode==RECOGNIZER_EXAMPLE && resultCode==RESULT_OK) {
    		// returned data is a list of matches to the speech input
    		ArrayList<String> result =
    				data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
    		//display on screen
    		searchFor.setText(result.get(0).toString());
    	}
    	super.onActivityResult(requestCode, resultCode, data);
    }

    
    /**
     * All overlay elements on a map are held by the MapView, so when you want to add some, 
     * you have to get a list from the getOverlays() method.
     * Then instantiate the Drawable used for the map marker, which was saved 
     * in the res/drawable/ directory. 
     * @param mapView
     */

    private void setupOverlay(MapView mapView, OverlayItem overlayitem){
    	Drawable drawable = this.getResources().getDrawable(R.drawable.map_marker);
    	CTItemizedOverlay itemizedoverlay = new CTItemizedOverlay2(drawable, this);
    	itemizedoverlay.addOverlay(overlayitem);

    	mapOverlays.add(itemizedoverlay);
    }
    
    private void setupOverlay(MapView mapView, GeoPoint p){
        OverlayItem overlayitem = new OverlayItem(p, "Here, you are!!", "I'm here!");
        setupOverlay(mapView, overlayitem);
    } 
    
    private void setupOverlay(MapView mapView, OverlayItem... overlayitems){
    	Drawable drawable = this.getResources().getDrawable(R.drawable.map_marker);
    	setupOverlay(mapView, drawable, overlayitems);
    	
    	/*
    	CTItemizedOverlay itemizedoverlay = new CTItemizedOverlay2(drawable, this);

    	for (OverlayItem overlayitem : overlayitems) {
        	itemizedoverlay.addOverlay(overlayitem);
        	mapOverlays.add(itemizedoverlay);    		
    	}
    	*/
    }
    
    private void setupOverlay(MapView mapView, Drawable d, OverlayItem... overlayitems){
    	CTItemizedOverlay itemizedoverlay = new CTItemizedOverlay2(d, this);

    	for (OverlayItem overlayitem : overlayitems) {
        	itemizedoverlay.addOverlay(overlayitem);
        	mapOverlays.add(itemizedoverlay);    		
    	}
    }    
    
    private void setupOverlay(MapView mapView, GeoPoint... points){
    	OverlayItem overlayitems[] = new OverlayItem[points.length];
    	for (int i=0; i< points.length; i++) {
    		overlayitems[i] = new OverlayItem(points[i], null, null);
    	}
        setupOverlay(mapView, overlayitems);
    }
    
    private void setupOverlay(MapView mapView, List<GeoPoint> points){
    	OverlayItem overlayitems[] = new OverlayItem[points.size()];
    	for (int i=0; i< points.size(); i++) {
    		overlayitems[i] = new OverlayItem(points.get(i), null, null);
    	}
        setupOverlay(mapView, overlayitems);
    }    
   
    private void setupOverlay(MapView mapView, List<GeoPoint> points, Drawable d){
    	OverlayItem overlayitems[] = new OverlayItem[points.size()];
    	for (int i=0; i< points.size(); i++) {
    		overlayitems[i] = new OverlayItem(points.get(i), null, null);
    	}
        setupOverlay(mapView, d, overlayitems);
    }    
     
    
    /**
     * This function will get points of friends to be obtained from server
     * @param p - this person's pointer
     */
    private List<GeoPoint> getOtherLocations(GeoPoint p){
    	List<GeoPoint> points = new ArrayList<GeoPoint>();
    	/**
    	 * current dummy point generator
    	 */
    	
    	points.add(new GeoPoint( (int) (p.getLatitudeE6()*1.00011), (int) (p.getLongitudeE6()*1.00011)) );
    	points.add(new GeoPoint( (int) (p.getLatitudeE6()*1.00031), (int) (p.getLongitudeE6()*1.0002)) );
    	
    	return points;
    }
    

    @Override
    protected boolean isRouteDisplayed() {
    	return false;
    }

	
	/*
    Handler mHandler = new Handler() {
        public void handleMessage(android.os.Message msg) {
	        	AlertDialog.Builder adb = new AlertDialog.Builder(MainUIMapActivity.this);
	        	adb.setTitle("Chal, Trojan!");
	        	adb.setMessage(mRoad.mName + " " + mRoad.mDescription);
	        	adb.setPositiveButton("Close",null);
	        	adb.show();

                RoadRouteOverlay mapOverlay = new RoadRouteOverlay(mRoad, mv);
                List<Overlay> listOfOverlays = mv.getOverlays();
                listOfOverlays.clear();
                listOfOverlays.add(mapOverlay);
                mv.invalidate();
        };
    };
    //*/

    static public String convertStreamToString(InputStream is) { 
    	   try {
    	        return new java.util.Scanner(is).useDelimiter("\\A").next();
    	    } catch (java.util.NoSuchElementException e) {
    	        return "";
    	    }
    }
   
    private class GetLocationTask extends AsyncTask<Void, Void, Void> {
    	JSONObject jsonObject;
    	String address;
    	Address[] addrs;
    	ProgressDialog pd;
    	
    	public GetLocationTask(String a, Address[] addrs) {
    		this.address = a;
    		this.addrs = addrs;
    		pd =  new ProgressDialog(SetDestinationMapActivity.this.getApplicationContext());
    	}
    	
    	@Override
    	protected void onPreExecute() {
    		// TODO Auto-generated method stub
    		super.onPreExecute();
    		pd = ProgressDialog.show(SetDestinationMapActivity.this, "Searching...", "Fetching results...");
    	}

    	@Override
    	protected Void doInBackground(Void... params) {
    		getLocationInfo(address);
    		return null;
    	}
    	
    	@Override
    	protected void onPostExecute(Void result) {
    		// TODO Auto-generated method stub
    		super.onPostExecute(result);
    		pd.dismiss();
    		//now we have to update UI:
    		locationFound(addrs[0]);
    		
    	}
    	

    	private void getLocationInfo(String address) {

    		String query = "http://maps.google.com/maps/api/geocode/json?address=" + address.replaceAll(" ","%20")
    				+ "&sensor=true";
    		Log.d("maps","query is --> "+query.toString());
    		Address addr = null;
    		HttpClient client = new DefaultHttpClient();
    		HttpGet httpGet = new HttpGet(query);

    		HttpResponse response;
    		StringBuilder stringBuilder = new StringBuilder();

    		try {
    			response = client.execute(httpGet);
    			if (response.getStatusLine().getStatusCode() == 200) {

    				HttpEntity entity = response.getEntity();
    				InputStream stream = entity.getContent();
    				int b;
    				while ((b = stream.read()) != -1) {
    					stringBuilder.append((char) b);
    				}
    				try {
    					jsonObject = new JSONObject(stringBuilder.toString());
    					addr = new Address(Locale.getDefault());
    					JSONArray addrComp = ((JSONArray)jsonObject.get("results")).getJSONObject(0)
    							.getJSONArray("address_components");
    					String locality = ((JSONArray)((JSONObject)addrComp.get(0)).get("types")).getString(0);
    					if (locality.compareTo("locality") == 0) {
    						locality = ((JSONObject)addrComp.get(0)).getString("long_name");
    						addr.setLocality(locality);
    					}
    					String adminArea = ((JSONArray)((JSONObject)addrComp.get(2)).get("types")).getString(0);
    					if (adminArea.compareTo("administrative_area_level_1") == 0) {
    						adminArea = ((JSONObject)addrComp.get(2)).getString("long_name");
    						addr.setAdminArea(adminArea);
    					}
    					String country = ((JSONArray)((JSONObject)addrComp.get(3)).get("types")).getString(0);
    					if (country.compareTo("country") == 0) {
    						country = ((JSONObject)addrComp.get(3)).getString("long_name");
    						addr.setCountryName(country);
    					}
    				} catch (JSONException e) {
    					//addr = null; //no results
    					e.printStackTrace();
    				}
    				Double lon = Double.valueOf(0);
    				Double lat = Double.valueOf(0);

    				try {

    					lon = ((JSONArray)jsonObject.get("results")).getJSONObject(0)
    							.getJSONObject("geometry").getJSONObject("location")
    							.getDouble("lng");

    					lat = ((JSONArray)jsonObject.get("results")).getJSONObject(0)
    							.getJSONObject("geometry").getJSONObject("location")
    							.getDouble("lat");

    				} catch (JSONException e) {
    					e.printStackTrace();
    				}
    				addr.setLatitude(lat);
    				addr.setLongitude(lon);
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		addrs[0] = addr;
    		if (addr != null) {
        		Log.d("maps","addrs[0] = "+addrs[0].toString());
    		} else {
    			addr = new Address(Locale.getDefault());
				addr.setLatitude(0.0);
				addr.setLongitude(0.0);
				addrs[0] = addr;
    		}
    	}
    }
  
    
}


/*




*/